package org.jxf.gps.jt808.server;




import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipelineCoverage;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ChildChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.WriteCompletionEvent;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.jboss.netty.handler.codec.http.HttpVersion;
import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;


@ChannelPipelineCoverage("all")
public class WebSocketServerHandler extends SimpleChannelHandler {
	
	private static Logger logger = Logger.getLogger(WebSocketServerHandler.class);

	@Override
	public void bindRequested(ChannelHandlerContext ctx, ChannelStateEvent e)
			throws Exception {
		
		super.bindRequested(ctx, e);
		logger.debug(this + " "+"bindRequested");
	}

	@Override
	public void channelBound(ChannelHandlerContext ctx, ChannelStateEvent e)
			throws Exception {
		
		super.channelBound(ctx, e);
		logger.debug(this + " "+"channelBound");
	}

	@Override
	public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
			throws Exception {
		
		super.channelClosed(ctx, e);
		logger.debug(this + " "+"channelClosed");
	}

	@Override
	public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
			throws Exception {
		
		super.channelConnected(ctx, e);
		logger.debug(this + " "+"channelConnected remote = " + e.getChannel().getRemoteAddress());
	}

	@Override
	public void channelDisconnected(ChannelHandlerContext ctx,
			ChannelStateEvent e) throws Exception {
		
		super.channelDisconnected(ctx, e);
		logger.debug(this + " "+"channelDisconnected");
	}

	@Override
	public void channelInterestChanged(ChannelHandlerContext ctx,
			ChannelStateEvent e) throws Exception {
		
		super.channelInterestChanged(ctx, e);
		logger.debug(this + " "+"channelInterestChanged");
	}

	@Override
	public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
			throws Exception {
		
		super.channelOpen(ctx, e);
		logger.debug(this + " "+"channelOpen remote = " + e.getChannel().getRemoteAddress() + " total="+Server.allChannels.size());
	}

	@Override
	public void channelUnbound(ChannelHandlerContext ctx, ChannelStateEvent e)
			throws Exception {
		
		super.channelUnbound(ctx, e);
		logger.debug(this + " "+"channelUnbound");
	}

	@Override
	public void childChannelClosed(ChannelHandlerContext ctx,
			ChildChannelStateEvent e) throws Exception {
		
		super.childChannelClosed(ctx, e);
		logger.debug(this + " "+"childChannelClosed remote = " + e.getChannel().getRemoteAddress());
	}

	@Override
	public void childChannelOpen(ChannelHandlerContext ctx,
			ChildChannelStateEvent e) throws Exception {
		
		super.childChannelOpen(ctx, e);
		logger.debug(this + " "+"childChannelOpen");
	}

	@Override
	public void closeRequested(ChannelHandlerContext ctx, ChannelStateEvent e)
			throws Exception {
		
		super.closeRequested(ctx, e);
		logger.debug(this + " "+"childChannelOpen");
	}

	@Override
	public void connectRequested(ChannelHandlerContext ctx, ChannelStateEvent e)
			throws Exception {
		
		super.connectRequested(ctx, e);
		logger.debug(this + " "+"connectRequested");
	}

	@Override
	public void disconnectRequested(ChannelHandlerContext ctx,
			ChannelStateEvent e) throws Exception {
		
		super.disconnectRequested(ctx, e);
		logger.debug(this + " "+"disconnectRequested");
	}

	@Override
	public void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e)
			throws Exception {
		
		super.handleDownstream(ctx, e);
		logger.debug(this + " "+"handleDownstream");
	}

	@Override
	public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e)
			throws Exception {
		
		super.handleUpstream(ctx, e);
		logger.debug(this + " "+"handleUpstream");
	}

	@Override
	public void setInterestOpsRequested(ChannelHandlerContext ctx,
			ChannelStateEvent e) throws Exception {
		
		super.setInterestOpsRequested(ctx, e);
		logger.debug(this + " "+"setInterestOpsRequested");
	}

	@Override
	public void unbindRequested(ChannelHandlerContext ctx, ChannelStateEvent e)
			throws Exception {
		
		super.unbindRequested(ctx, e);
		logger.debug(this + " "+"unbindRequested");
	}

	@Override
	public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e)
			throws Exception {
		
		super.writeComplete(ctx, e);
		logger.debug(this + " "+"writeComplete");
	}

	@Override
	public void writeRequested(ChannelHandlerContext ctx, MessageEvent e)
			throws Exception {
		
		super.writeRequested(ctx, e);
		logger.debug(this + " "+"writeRequested");
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
			throws Exception {
		
		super.exceptionCaught(ctx, e);
		logger.error(this + " "+"exceptionCaught",e.getCause());
	}
	
	
    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
        Channel ch = e.getChannel();
        Object msg = e.getMessage();
         

        	logger.debug("---------------");
        	logger.debug("message: "+msg.getClass());

        //虽然是websocket，但在建立websocket连接前，先进行http握手,所以，这时也要处理http请求
        //在http握手完成后，才是websocket下的通信
        if(msg instanceof HttpRequest){
            processHttpRequest(ch, (HttpRequest)msg);
        }else if(msg instanceof WebSocketFrame){
            processWebsocketRequest(ch,(WebSocketFrame)msg);
        }else{
            //未处理的请求类型
        }
    }
     
    //这个方法：
    //1.完成websocket前的http握手
    //2.屏蔽掉非websocket握手请求
    void processHttpRequest(Channel channel,HttpRequest request){
        List headers = request.getHeaders();
        List<Map.Entry<String,String>> ls = headers;
        String upgrade = "";
        String host = "";
        for(Map.Entry<String,String> i: ls){
            System.out.println("header  "+i.getKey()+":"+i.getValue());
            if ("Upgrade".equals(i.getKey())){
            	upgrade = i.getValue();
            }
            if (HttpHeaders.Names.HOST.equals(i.getKey())){
            	host = i.getValue();
            }
        }
        
        //屏蔽掉非websocket握手请求
        //只接受http GET和headers['Upgrade']为'websocket'的http请求
        if(!HttpMethod.GET.equals(request.getMethod())
                || !"websocket".equalsIgnoreCase(upgrade)){
            DefaultHttpResponse resp = new DefaultHttpResponse(
                    HttpVersion.HTTP_1_1,
                    HttpResponseStatus.BAD_REQUEST);
            channel.write(resp);            
            channel.close();
            return;
        }
         
        WebSocketServerHandshakerFactory wsShakerFactory = new WebSocketServerHandshakerFactory(
                "ws://"+host,
                null,false );
        WebSocketServerHandshaker wsShakerHandler = wsShakerFactory.newHandshaker(request);
        if(null==wsShakerHandler){
            //无法处理的websocket版本
            wsShakerFactory.sendUnsupportedWebSocketVersionResponse(channel);
        }else{
            //向客户端发送websocket握手,完成握手
            //客户端收到的状态是101 sitching protocol
            wsShakerHandler.handshake(channel, request);
        }       
    }
     
    //websocket通信
    void processWebsocketRequest(Channel channel, WebSocketFrame request){      
        if(request instanceof CloseWebSocketFrame){
            channel.close();
        }else if(request instanceof PingWebSocketFrame){         
            channel.write(new PongWebSocketFrame(request.getBinaryData()));  
        }else if(request instanceof TextWebSocketFrame){
            //这个地方 可以根据需求，加上一些业务逻辑
            TextWebSocketFrame txtReq = (TextWebSocketFrame) request;
            logger.debug("txtReq:"+txtReq.getText());
             
            //向ws客户端发送多个响应
            for(int i=1; i<=20; i++){
                channel.write(new TextWebSocketFrame(""+i));
                try{Thread.sleep(300);}catch(Exception ex){}
            }           
        }else{
            //WebSocketFrame还有一些
        }
    }

}
